;; Platform-specific stuff!!!!
(setq document-view "setsid -w xdg-open %s"
      pdf-viewer "Evince" ; for C-c C-v LaTeX forward search
      keepass-folder "~/Syncthing/keepass/"
      bibliography-folder "~/Documents/bibliography/"
      biblio-key (kbd "<f12>") ; use <apps> for the menu button in
                               ; other OS's, or for example <f12> for
                               ; Termux and see its wiki for showing
                               ; this button on its interface. Also
                               ; <X86Launch1> works in Mate desktop,
                               ; but not terminals.
      windmove-key 'shift ; for 'shift, see
                          ; https://emacs.stackexchange.com/a/54002
;;       browse-url-browser-function 'browse-url-xdg-open ; in termux
      org-replace-disputed-keys t ; for windmove when using 'shift
      want-to-use-xclip nil ; termux clipboard, install termux-api too
)
;; Computed stuff:
(setq own-calendar-file (concat keepass-folder "calendar.org")
      own-bookmark-file (concat keepass-folder "bookmarks.org")
      gtd-folder (concat keepass-folder "gtd/")
      gtd-inbox (concat gtd-folder "inbox.org")
      gtd-gtd (concat gtd-folder "gtd.org")
      gtd-someday (concat gtd-folder "someday.org")
      gtd-archive (concat gtd-folder "archive.org")
      gtd-tickler (concat gtd-folder "tickler.org")
      bibliography-file (concat bibliography-folder "references.bib")
      bibliography-pdf-folder (concat bibliography-folder "bibtex-pdfs/")
      bibliography-notes (concat bibliography-folder "bibtex-notes/"))


;; Defer loading packages unless daemon
(setq use-package-always-demand (daemonp))

;; Always revert files, i.e. reload them to buffers if emacs notices
;; them changing by e.g. an external program.
(global-auto-revert-mode 1)

;; Load the MELPA package library
(require 'package)
(add-to-list 'package-archives '("melpa"
             . "https://melpa.org/packages/") t)
(package-initialize)

;; Download and load use-package
(unless (package-installed-p 'use-package)
  (package-install 'use-package))

;; Make garbage collection less frequent
;; then put to normal at the end of init
(setq gc-cons-threshold (* 50 1000 1000))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; General text file handling ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Coding system
(set-language-environment    "UTF-8")
(setq locale-coding-system   'utf-8)
(prefer-coding-system        'utf-8)
(set-default-coding-systems  'utf-8)
(set-terminal-coding-system  'utf-8)
(set-keyboard-coding-system  'utf-8)
(set-selection-coding-system 'utf-8)
(setq-default buffer-file-coding-system 'utf-8)
(add-to-list 'safe-local-variable-values '(buffer-file-coding-system . utf-8))
;; Backups into ~/.emacs-saves
(unless (file-exists-p "~/.saves-emacs")
  (make-directory "~/.saves-emacs"))
(setq backup-directory-alist '(("." . "~/.saves-emacs"))
      backup-by-copying t
      delete-old-versions t
      kept-new-versions 6
      kept-old-versions 2
      version-control t)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;;;;;;;;;;;;;;;;;;;;;;;
;;;; Email related ;;;;
;;;;;;;;;;;;;;;;;;;;;;;
(setq mail-user-agent 'gnus-user-agent
      epg-pinentry-mode 'loopback) ; Avoids GPG password input entry
                                   ; issue in emacs termux. Might need
                                   ; to edit .gnupeg/gpg-agent.conf
                                   ; and add "allow-emacs-pinentry"
;; BBDB settings
(use-package bbdb
  :ensure t
  :custom
  (bbdb-file (concat keepass-folder "bbdb"))
  (bbdb-mua-pop-up t) ; Display BBDB in popup window
  (bbdb-mua-pop-up-window-size 3)
  (bbdb-mua-update-interactive-p
   '(query . create)) ; Look for existing contact, interactively
                      ; prompt to create
  :config
  (bbdb-initialize 'gnus 'message)
  (bbdb-mua-auto-update-init 'gnus 'message))
;;;;;;;;;;;;;;;;;;;;;;;


;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; Appearance related ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Nyan-mode.
(use-package nyan-mode
  :ensure t
  :config
  (nyan-mode 1)
  (nyan-start-animation)
  ;; Install sox in termux to play music and uncomment below.
  ;; (defun nyan-start-music ()
  ;;   (interactive)
  ;;   (unless nyan-music-process
  ;;     (setq nyan-music-process (start-process-shell-command "nyan-music" "nyan-music" (concat "play " +nyan-music+ " repeat 9001")))))
  )
;; Bar instead of cursor & highlight it on buffer change
(setq-default cursor-type 'bar)
(use-package beacon
  :ensure t
  :defer t
  :init  (beacon-mode 1)
  :bind ("C-:" . beacon-blink)
  :config
  (setq beacon-blink-when-window-scrolls nil))
;; Mixed pitch font in latex and org
(use-package mixed-pitch
  :ensure t
  :defer t
  :config
  (with-eval-after-load 'org
    (add-to-list 'mixed-pitch-fixed-pitch-faces 'org-todo)
    (add-to-list 'mixed-pitch-fixed-pitch-faces 'org-done)
    (add-to-list 'mixed-pitch-fixed-pitch-faces 'org-my-meet)
    (add-to-list 'mixed-pitch-fixed-pitch-faces 'org-my-wait))
  :hook ((org-mode   . mixed-pitch-mode)
         (LaTeX-mode . mixed-pitch-mode)))
;; Font selection (update per display DPI)
(when (member "Fragment Mono" (font-family-list))
  (set-face-attribute 'default nil :font "Fragment Mono")
  (set-face-attribute 'fixed-pitch nil :family "Fragment Mono"))
(when (member "Open Sans" (font-family-list))
  (set-face-attribute 'variable-pitch nil :family "Open Sans"))
;; Based on
;; - https://github.com/mnp/dispwatch
;; - https://emacs.stackexchange.com/a/36074
;; - https://emacs.stackexchange.com/a/44930
(defun my-dpi ()
  (let* ((attrs (frame-monitor-attributes))
         (size (assoc 'mm-size attrs))
         (sizex (cadr size))
         (resx (cadddr (assoc 'workarea attrs)))
         dpi)
    (catch 'exit
      ;; in terminal
      (unless sizex
        (throw 'exit 10))
      ;; DPI
      (* (/ (float resx) sizex) 25.4))))
(defun my-preferred-font-size ()
  (let ( (dpi (my-dpi)) )
    (cond
     ((< dpi 100) 130) ; TV 67 dpi (size 130)
     ((< dpi 160) 110) ; Work desktop 108 dpi (size 110)
     (t 130)))) ; Dell 168 dpi (size 130)
(defun my-set-font-sizes-by-dpi ()
  (let* ((mpfs (my-preferred-font-size)))
    (message "setting font height to %s" mpfs)
    (when (member "Fragment Mono" (font-family-list))
      (set-face-attribute 'default nil :height mpfs)
      (set-face-attribute 'fixed-pitch nil :height mpfs))
    (when (member "Open Sans" (font-family-list))
      (set-face-attribute 'variable-pitch nil :height mpfs))))
(defun my-set-font-sizes-by-dpi-for-disp (disp)
  (message "rejiggering for %s" disp)
  (my-set-font-sizes-by-dpi))
(use-package dispwatch
  :ensure t
  :config (and
      (add-hook 'dispwatch-display-change-hooks #'my-set-font-sizes-by-dpi-for-disp)
      (dispwatch-mode 1)
      (my-set-font-sizes-by-dpi)))


;; Theme
(use-package nord-theme ; Good candidates: nord-theme, dracula-theme
  :ensure t)
(use-package nano-theme
  :ensure t
  :config
  (defun my-fix-nano-gnus (orig-fun &rest args)
    (apply orig-fun args)
    (if (member (car args) '(nano nano-light nano-dark))
        (progn
          (custom-theme-set-faces ; Emphasise important gnus groups and emails 
           (car args)
           '(variable-pitch                         ((t (:inherit nano-default))))
           '(gnus-group-mail-1                      ((t (:inherit nano-strong))))
           '(gnus-group-mail-1-empty                ((t (:inherit nano-faded))))
           '(gnus-group-mail-2                      ((t (:inherit nano-default))))
           '(gnus-group-mail-2-empty                ((t (:inherit nano-faded))))
           '(gnus-group-news-1                      ((t (:inherit nano-strong))))
           '(gnus-group-news-1-empty                ((t (:inherit nano-faded))))
           '(gnus-group-news-2                      ((t (:inherit nano-default))))
           '(gnus-group-news-2-empty                ((t (:inherit nano-faded))))
           '(gnus-group-news-3                      ((t (:inherit nano-faded))))
           '(gnus-summary-normal-ancient            ((t (:inherit nano-faded))))
           '(gnus-summary-normal-read               ((t (:inherit nano-faded))))
           '(gnus-summary-normal-ticked             ((t (:inherit nano-strong))))
           '(gnus-summary-normal-undownloaded       ((t (:inherit nano-faded))))
           '(gnus-summary-normal-unread             ((t (:inherit nano-normal))))
           '(gnus-summary-selected                  ((t (:inherit)))))
          (message "Enabling theme %S with modifications." (car args))
          (enable-theme (car args))
          (if (equal system-type 'android)
              (if (member (car args) '(nano nano-light))
                  (start-process-shell-command "Change termux theme to light" nil "~/change-theme-light.sh")
                (start-process-shell-command "Change termux theme to dark" nil "~/change-theme-dark.sh"))))))
  (advice-add 'load-theme :around 'my-fix-nano-gnus))
(use-package theme-changer
  :ensure t
  :defer 0.01
  :after nano-theme
  :init
  (setq calendar-location-name "Espoo")
  (setq calendar-latitude 60.18)
  (setq calendar-longitude 24.82)
  :config
  (change-theme 'nano-light 'nano-dark))
;; Color issues
(setq shr-use-colors nil) ; Don't use text color when rendering html
                          ; using shr (links ok)
;; Olivetti mode for org-mode etc long texts.
;; Add
;; ((nil . ((fill-column . 80)
;;         (mode . olivetti))))
;; inside a folder's .dir-locals.el to use olivetti for all files there
(use-package olivetti
  :ensure t
  :defer t
  :config
  (setq gnus-treat-fill-long-lines nil)
  :hook
  ((latex-mode LaTeX-mode org-mode) . olivetti-mode)
  ((latex-mode LaTeX-mode org-mode)
   .
   (lambda () (auto-fill-mode -1))))
(use-package adaptive-wrap
  :ensure t
  :defer t
  :hook
  (visual-line-mode . adaptive-wrap-prefix-mode))
(global-visual-line-mode t) ;; Break lines instead of truncating them
(use-package writeroom-mode ; for clutter-free writing
  :ensure t
  :defer t)
(use-package writegood-mode ; for M-x writegood-mode to avoid passive tense etc
  :ensure t
  :defer t)
(use-package jinx ; for spellchecking, requires the enchant-2 library (+voikko for Finnish)
  ;; install in Windows using: https://github.com/minad/jinx/issues/10
  :ensure t
  :hook (emacs-startup . global-jinx-mode)
  :bind (("M-$"   . jinx-correct)
         ("C-M-$" . jinx-languages))
  :config
  (setq jinx-languages "en_GB fi")) ; fi requires voikko
;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; Emacs (mini-)buffer etc. behaviour ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; type ~ in minibuffer to go to home directory directly
(defun emilia/take-me-home ()
  (interactive)
  (if (looking-back "/" nil)
      (progn (call-interactively 'delete-minibuffer-contents) (insert "~/"))
    (call-interactively 'self-insert-command)))
;; Completion in M-x, filenames, etc
(use-package vertico
  :ensure t
  :bind (:map vertico-map (("~" . emilia/take-me-home)
                           ("TAB" . minibuffer-complete)))
  :config
  (vertico-mode 1)
  (vertico-multiform-mode 1)
  (setq read-extended-command-predicate       'command-completion-default-include-p
        vertico-multiform-commands            '(t (:not posframe))
        vertico-count                         28  ; Show more candidates
        read-file-name-completion-ignore-case t   ; Ignore case of file names
        read-buffer-completion-ignore-case    t   ; Ignore case in buffer completion
        completion-ignore-case                t)) ; Ignore case in completion
(use-package marginalia ; annotations in the minibuffer
  :ensure t
  :init
  (marginalia-mode 1))
(use-package vertico-posframe
  :ensure t
  :init
  (setq vertico-posframe-parameters
        '((left-fringe  . 12)    ;; Fringes
          (right-fringe . 12)
          (undecorated  . nil))) ;; Rounded frame
  :config
  (vertico-posframe-mode 1)
  (setq vertico-posframe-width        nil                       ;; Default width
        vertico-posframe-height       vertico-count)            ;; Default height
  ;; Make embark-act windows also in posframe instead of behind (since I'm using vertico-posframe)
  ;; https://emacs-china.org/t/vertico-posframe-embark-buffer/28610/6
  (progn
    (defun posframe-display-buffer (buffer)
      (let ((default-fgc (face-attribute 'default :foreground))
            (default-bgc (face-attribute 'default :background))
            (hl (face-attribute 'highlight :background)))
        (when buffer (posframe-show
        	      buffer
        	      :position (point)
        	      :poshandler 'posframe-poshandler-frame-center
        	      :font-height 1.0
        	      :font-width 1.0
        	      :width 120
        	      :height 20
        	      :border-width 5
        	      :left-fringe 20
        	      :right-fringe 20
        	      :border-color hl
        	      :background-color default-bgc))))
    (defvar embark-get-buffer-pos-display-orig-result nil
      "Variable to store the original result in embark-get-buffer-pos-display.")
    (defun embark-get-buffer-pos-display (orig-fun)
      (interactive)
      (setq embark-get-buffer-pos-display-orig-result (funcall orig-fun))
      (lambda (&optional keymap targets prefix)
        (let ((result (funcall embark-get-buffer-pos-display-orig-result keymap targets prefix)))
          (when (and result (windowp result))
            (posframe-display-buffer (window-buffer result))
            (delete-window result)))))
    (advice-add #'embark-verbose-indicator :around #'embark-get-buffer-pos-display)))
(use-package orderless
  :ensure t
  :demand t ; force loading
  :config
  (setq completion-styles '(orderless basic partial-completion)
        completion-category-overrides '((file (styles basic partial-completion)))
        orderless-component-separator "[ |]"))
;; Expand region
(use-package expand-region
  :ensure t
  :config
  (global-set-key (kbd "<f11>") 'er/expand-region)
  (delete-selection-mode t) ; typed text replaces the selection
  )
;; Smartparens
(use-package smartparens
  :ensure t
  :hook
  ((lisp-mode emacs-lisp-mode gfm-mode markdown-mode LaTeX-mode)
  . show-paren-mode)
  ((lisp-mode emacs-lisp-mode gfm-mode markdown-mode LaTeX-mode)
  . smartparens-mode)
  :config
  (sp-local-pair '(lisp-mode emacs-lisp-mode) "'" nil :actions nil)
  (sp-local-pair '(lisp-mode emacs-lisp-mode) "`" nil :actions nil)
  ;; Add \big( \big), etc. without having to use \bigl( \bigr).
  (sp-with-modes '(tex-mode plain-tex-mode latex-mode LaTeX-mode)
    (sp-local-pair "\\big(" "\\big)" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\bigg(" "\\bigg)" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\Big(" "\\Big)" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\Bigg(" "\\Bigg)" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\big[" "\\big]" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\bigg[" "\\bigg]" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\Big[" "\\Big]" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\Bigg[" "\\Bigg]" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\big\\{" "\\big\\}" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\bigg\\{" "\\bigg\\}" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\Big\\{" "\\Big\\}" :post-handlers '(sp-latex-insert-spaces-inside-pair))
    (sp-local-pair "\\Bigg\\{" "\\Bigg\\}" :post-handlers '(sp-latex-insert-spaces-inside-pair)))
  (eval-after-load 'latex '(require 'smartparens-latex))
  )
(winner-mode t) ; C-c ←/→ for going between used window configurations
(use-package transpose-frame
  :ensure t
  :bind
  ("C-x |" . transpose-frame))
(setq-default word-wrap nil)
(defun unfill-paragraph () ; for copy-pasting to external program
  "Takes a multi-line paragraph and makes it into a single line of text."
  (interactive)
  (let ((fill-column (point-max)))
    (fill-paragraph nil)))
(define-key global-map "\M-Q" 'unfill-paragraph) ; alt+shift+q
;; Sort words
;; https://www.emacswiki.org/emacs/SortWords
(defun sort-words (reverse beg end)
  "Sort words in region alphabetically, in REVERSE if negative.
    Prefixed with negative \\[universal-argument], sorts in reverse.
  
    The variable `sort-fold-case' determines whether alphabetic case
    affects the sort order.
  
    See `sort-regexp-fields'."
  (interactive "*P\nr")
  (sort-regexp-fields reverse "\\w+" "\\&" beg end))
(windmove-default-keybindings windmove-key)
(setq mouse-yank-at-point t) ; Use current cursor position for middle
                             ; mouse pasting instead of jumping to new
                             ; location then paste
;; F9 opens file where we save www-bookmarks
(global-set-key (kbd "<f9>") (lambda() (interactive)(find-file own-bookmark-file)))
;; Xclip
(when want-to-use-xclip
  (use-package xclip
    :ensure t
    :config
    (xclip-mode 1)
    ))
;; Scroll speed
(setq scroll-conservatively            101
      mouse-wheel-follow-mouse         't
      mouse-wheel-progressive-speed    nil
      ;; Scroll 1 line at a time, instead of default 5
      ;; Hold shift to scroll faster and meta to scroll very fast
      mouse-wheel-scroll-amount        '(1 ((shift) . 3) ((meta) . 6)))
;; (Native) smooooooth scrolling
(setq pixel-scroll-precision-mode t)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;;;;;;;;;;;;;;;;;;;;;;;;
;;;; Coding related ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;
(global-set-key "\C-x\C-m" 'compile) ; C-x C-m compile
(setq compilation-read-command nil ; compile with "make -k"
      compilation-scroll-output t) ; autoscroll compilation buffer
(use-package magit
  :ensure t
  :bind
  ("C-x g" . magit-status)
  :custom
  (magit-diff-refine-hunk 'all))
(use-package abridge-diff
  :ensure t
  :after magit
  :init (abridge-diff-mode 1))
;; Completion
(use-package company
  :ensure t
  :hook
  ((emacs-lisp-mode latex-mode LaTeX-mode) . company-mode)
  :custom
  (company-tooltip-align-annotations 1)
  (company-minimum-prefix-length 1)
  (company-idle-delay 0.0)
  (company-selection-wrap-around t)
  (company-dabbrev-ignore-case nil)
  (company-dabbrev-downcase nil)
  :config
  (company-tng-mode)
  (define-key company-active-map [up] nil)
  (define-key company-active-map [down] nil)
  (define-key company-active-map [tab] nil)
  (define-key company-active-map (kbd "TAB") nil)
  (define-key company-active-map (kbd "<C-tab>") 'company-complete-common-or-cycle)
  (define-key company-active-map (kbd "C-<iso-lefttab>") 'company-cycle-backward)
  (define-key company-tng-map [tab] nil)
  (define-key company-tng-map (kbd "TAB") nil)
  (define-key company-tng-map [backtab] nil)
  (define-key company-tng-map (kbd "S-TAB") nil)
  (define-key company-tng-map (kbd "<C-tab>") 'company-select-next)
  (define-key company-tng-map [C-backtab] 'company-select-previous)
  (define-key company-tng-map (kbd "C-<iso-lefttab>") 'company-select-previous))

(use-package company-reftex
  :ensure t
  :after (reftex company)
  :hook
  ((latex-mode LaTeX-mode) . (lambda ()
                               (set (make-local-variable 'company-backends)
                                    '((company-reftex-labels company-reftex-citations company-dabbrev)))))
  :custom
  (company-reftex-labels-regexp
   (rx "\\"
       ;; List taken from `reftex-ref-style-alist'
       (or "autoref"
           "autopageref"
           "Cpageref"
           "cpageref"
           "Cref"
           "cref"
           "eqref"
           "Fref"
           "fref"
           "pageref"
           "Ref"
           "ref"
           "vpageref"
           "Vref"
           "vref"
           ;; own stuff:
           "ilo")
       "{"
       (group (* (not (any "}"))))
       (regexp "\\="))
   "Regular expression to use when lookng for the label prefix.
Group number 1 should be the prefix itself."
   :type 'string
   :group 'company-reftex)
  )

(use-package slime ; SLIME (Common LISP)
  :ensure t
  :defer
  :custom
  (inferior-lisp-program "clisp")
  :config
  (slime-setup '(slime-fancy)))
(use-package slime-company
  :ensure t
  :defer
  :after (slime company)
  :custom
  (slime-company-completion 'fuzzy)
  :config
  (slime-setup '(slime-company)))
(use-package geiser-chez ; For Chez Scheme, start M-x run-geiser
  :ensure t
  :defer)
(use-package markdown-mode
  :ensure t
  :defer
  :mode ("README\\.md\\'" . gfm-mode)
  :custom
  (markdown-command "pandoc"))
;; Indentation & behaviour
(defun infer-indentation-style ()
  "Default to no tabs, but use tabs if already in project"
  (let ((space-count (how-many "^  " (point-min) (point-max)))
        (tab-count   (how-many "^\t" (point-min) (point-max))))
    (if (> space-count tab-count) (setq-default indent-tabs-mode nil))
    (if (> tab-count space-count) (setq-default indent-tabs-mode t))))
(setq-default indent-tabs-mode nil
              standard-indent 2)
(infer-indentation-style)
;; C-a and C-e moves to beginning and syntactic element respecting indentation
(use-package mwim
  :ensure t
  :bind (("C-a" . mwim-beginning-of-code-or-line)
         ("C-e" . mwim-end-of-code-or-line)))
;;;;;;;;;;;;;;;;;;;;;;;;




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; LaTeX / math /calc related ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(add-to-list 'auto-mode-alist '("\\.m\\'" . octave-mode))
(setq bibtex-align-at-equal-sign t) ; align = in bibtex using C-c C-q
(if (display-graphic-p)
    (progn
      (use-package pdf-tools
        :ensure t
        :defer
        :config
        (pdf-tools-install :no-query))
      (use-package doc-view ; warn when opening a document using doc-view instead of pdf-tools
        :hook (doc-view-mode . (lambda ()
                                 (display-warning
                                  emacs
                                  "Oops, using DocView instead of PDF Tools!"
                                  :warning))))
      (use-package org-noter
        :ensure t
        :defer
        :after (pdf-tools)
        :custom
        (org-noter-notes-search-path (list bibliography-notes)))))
(use-package tex
  :ensure auctex
  :after cdlatex
  :custom
  (TeX-source-correlate-mode t) ; for forward search
  :config
  ;; Make sure that when tabbing in org-cdlatex-mode it will not
  ;; complain of missing "LaTeX-indent-line".
  (defun own-LaTeX-indent-line ()
    (when (or (eq major-mode 'LaTeX-mode)
              (eq major-mode 'latex-mode))
      (LaTeX-indent-line)))
  (add-hook 'cdlatex-tab-hook 'own-LaTeX-indent-line)
  (add-to-list 'TeX-view-program-selection
               `(output-pdf ,pdf-viewer)) ; ` is like quote but allows
                                          ; evaluation inside using ,
  :hook
  ; Make \ part of words in LaTeX-mode
  ((latex-mode LaTeX-mode) . (lambda () (modify-syntax-entry
                                         (string-to-char TeX-esc)
                                         "w"
                                         LaTeX-mode-syntax-table))))
(use-package cdlatex
  :ensure t
  :custom
  (cdlatex-takeover-parenthesis . nil)
  :hook
  ((latex-mode LaTeX-mode) . cdlatex-mode)
  (org-mode . turn-on-org-cdlatex)
  :config
  (setq cdlatex-env-alist
        '(("definition" "\\begin{definition} AUTOLABEL\n?\n\\end{definition}\n" nil)
          ("theorem" "\\begin{theorem} AUTOLABEL\n?\n\\end{theorem}\n" nil)
          ("lemma" "\\begin{lemma} AUTOLABEL\n?\n\\end{lemma}\n" nil)))
  (setq cdlatex-command-alist
        '(("def" "Insert definition env"   "" cdlatex-environment ("definition") t nil)
          ("thm" "Insert theorem env"   "" cdlatex-environment ("theorem") t nil)
          ("lem" "Insert lemma env"   "" cdlatex-environment ("lemma") t nil)
          ("wt" "Insert \\widetilde{}" "\\widetilde{?}" cdlatex-position-cursor nil nil t))))

(use-package reftex
  :ensure t
  :hook
  ((latex-mode LaTeX-mode) . turn-on-reftex))
(use-package bibtex
  :custom
  ;; Ignore only lower case title words instead of all non-uppercased
  ;; ones when generating keys for bibtex
  (bibtex-autokey-titleword-ignore
   '("A" "An" "On" "The" "Eine?" "Der" "Die" "Das" "[[:lower:]].*" ".*[^[:upper:][:lower:]0-9].*")))
;; Handle references, citar-xxx for actions, use with embark
(use-package citar
  :ensure t
  :demand t
  :bind (:map citar-map
              ("m" . citar-attach-files))
  :custom
  (citar-bibliography (list bibliography-file))
  (citar-library-paths (list bibliography-pdf-folder))
  (citar-notes-paths  (list bibliography-notes))
  (citar-file-open-functions
   '((t . org-open-file)))
  (citar-templates
   '((main    . "${author editor:30%sn} | ${date year issued:4} | ${title:48}")
     (suffix  . " | ${=type=:6} | ${tags keywords keywords:*}")
     (preview . "${author editor:%etal} (${year issued date}) ${title}, ${journal journaltitle publisher container-title collection-title}.")
     (note    . "Notes on ${author editor:%etal}, ${title}")))
  :config ; can't have a form like biblio-key under :bind
  (bind-key biblio-key citar-map))
(use-package embark
  :ensure t
  :bind (("C-." . embark-act)
         ("C-h B" . embark-bindings)))
(use-package citar-embark
  :ensure t
  :after citar embark
  :no-require
  :config (citar-embark-mode 1))
(use-package bibtex-completion
  :ensure t
  :custom
  ;; Location of bibliography for bibtex-completion internals. Follow
  ;; https://github.com/jkitchin/org-ref/?tab=readme-ov-file#configuration
  ;; if wanting to use with org-ref for inserting citations and
  ;; opening them in org-files.
  ;; TODO: remove citar, and rely more on this and org-ref?
  (bibtex-completion-bibliography bibliography-file)
  (bibtex-completion-library-path bibliography-pdf-folder)
  (bibtex-completion-notes-path bibliography-notes)
  (bibtex-completion-pdf-open-function
   (lambda (fpath)
     (call-process "open" nil 0 nil fpath))))
(use-package org-ref ; Includes doi-utils
  :ensure t
  :after bibtex-completion
  :bind (:map org-mode-map
              ("C-c C-x @" . org-ref-insert-link))
  :custom
  ;; Words which shouldn't be capitalized in titles
  (org-ref-lower-case-words '("a" "an" "at" "on" "and" "for" "the" "of" "in"))
  ;; Allow the following fields Into Title Case of the Following Items
  (org-ref-title-case-types '(("article" "title")
                              ("book" "booktitle")
                              ("misc" "title")))
  ;; Don't convert ä,ö,å, etc when org-ref-clean-bibtex-entry
  (org-ref-clean-bibtex-entry-hook
   '(org-ref-bibtex-format-url-if-doi orcb-key-comma orcb-& orcb-% org-ref-title-case orcb-clean-year orcb-key orcb-clean-doi orcb-clean-pages orcb-check-journal org-ref-sort-bibtex-entry orcb-fix-spacing))
  :config
  (custom-set-faces
   '(org-ref-cite-face ((t (:inherit org-link))))
   '(org-ref-label-face ((t (:inherit org-link))))
   '(org-ref-ref-face ((t (:inherit org-link))))
   ))
(use-package emacsql :ensure t)
(use-package org-roam
  :ensure t
  :defer
  :after emacsql
  :init
  (setq org-roam-database-connector 'sqlite-builtin)
  :custom
  (org-roam-directory bibliography-notes)
  (org-roam-capture-templates
   `(("d" "default" plain "%?"
      :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}")
      :unnarrowed t)
     ("b" "bibliography notes" plain             ; Org-noter integration
      (file ,(concat bibliography-notes "notes-template.org"))
      :target (file+head "${citekey}.org" "#+title: ${title}\n")
      :unnarrowed t)))
  :config
  (org-roam-db-autosync-mode 1))
(use-package org-roam-bibtex
  :ensure t
  :defer
  :custom
  (orb-preformat-keywords '("citekey" "title" "url" "author-or-editor" "keywords" "file")) ; customisation for notes, org-noter integration
  (orb-process-file-keyword t)
  (orb-attached-file-extensions '("pdf"))
  ;;(bibtex-completion-edit-notes-function 'bibtex-completion-edit-notes-default) ; default to org-ref for notes
  (bibtex-completion-edit-notes-function 'orb-bibtex-completion-edit-note) ; use org-roam-capture-templates for notes
  :config
  (require 'org-ref))
(use-package org-roam-ui
  :ensure t
  :after org-roam
  :custom
  (org-roam-ui-sync-theme t)
  (org-roam-ui-follow t)
  (org-roam-ui-update-on-save t)
  (org-roam-ui-open-on-start t))
(use-package casual
  :ensure t
  :after calc
  :bind (:map calc-mode-map ("C-o" . 'casual-calc-tmenu))
  )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;





;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; Org-mode related ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;
(use-package org
  :ensure t
  :bind
  ("C-c l" . org-store-link)
  ("C-c a" . org-agenda)
  ("C-c c" . org-capture)
  :custom
  (org-agenda-files (list own-calendar-file
                          gtd-inbox
                          gtd-gtd
                          gtd-tickler
                          gtd-someday))
  (org-agenda-start-on-weekday 1) ; nil means current day
  (org-agenda-span 7)
  (org-refile-targets '((org-agenda-files :maxlevel . 9)
                        (gtd-inbox :maxlevel . 3)
                        (gtd-someday :maxlevel . 2)
                        (gtd-tickler :maxlevel . 2)
                        (gtd-archive :level . 1)))
  (org-archive-reversed-order t) ; same for archiving with C-c C-x A
  (org-refile-use-outline-path t)
  (org-todo-keywords
   '((sequence "TODO(t)" "MEET(m)" "WAIT(w@)"
               "|" "DONE(d)" "KILL(k@)")))
  (org-todo-repeat-to-state t)
  (org-log-done 'time)
  (org-list-allow-alphabetical t)
  (org-cite-global-bibliography (list bibliography-file))
  ;; See see http://cachestocaches.com/2016/9/my-workflow-org-agenda/
  (org-capture-templates
   `(("t" "Todo [gtd inbox]" entry (file+headline ,gtd-inbox "Tasks")
      "* TODO %i%? %A")
     ("T" "Tickler" entry (file+headline ,gtd-tickler "Tickler")
      "* %i%? \n%T")
     ("m" "Meeting" entry (file+headline ,gtd-inbox "Tasks")
      "* MEET %i%? %A")
     ("b" "Bookmark" entry (file+headline ,own-bookmark-file "Bookmarks")
      "* %x %?%^g\n:PROPERTIES:\n:CREATED: %U\n:END:\n\n" :empty-lines-before 1)
     ("n" "Pdf note from email" plain (file ,bibliography-file)
      "@misc{????,\nauthor = {%^{author}},\nday = %^{day},\nmonth = %^{month},\nyear = %^{year},\ntags = {%^{comma-separated tags}},\ntitle = {%\\4/%\\3/%\\2 Notes - %^{topic (remember to save the PDF from email!!)}},\nurl = {%l}\n}\n\n" :empty-lines 1 :before-finalize org-ref-clean-bibtex-entry :immediate-finish 1)))
  ;; Org & agenda look
  (org-todo-keyword-faces '(("MEET" . org-my-meet)
                            ("WAIT" . org-my-wait)))
  (org-agenda-prefix-format
   '((agenda . " %i %?-12t% s") ; default: " %i %-12:c%?-12t% s"
     (todo . " %i %-12:c")
     (tags . " %i %-12:c")
     (search . " %i %-12:c")))
  (org-format-latex-options '(:foreground default
                              :background default
                              :scale 1.0
                              :html-foreground "Black"
                              :html-background "Transparent"
                              :html-scale 1.0
                              :matchers ("begin" "$1" "$" "$$" "\\(" "\\[")))
  (org-outline-path-complete-in-steps nil) ; for completions to work in Helm
  :config
  (defface org-my-meet
    '((t . (:foreground "#486f66"
            :background "#f4bbce"
            :weight ultra-bold)))
    "My custom face for the org-todo state MEET. Thick green on pink backgroun.")
  (defface org-my-wait
    '((t . (:foreground "orange"
            :weight ultra-bold)))
    "My custom face for the org-todo state WAIT. Tick orange.")
  ;; Open pdf & djvu outside emacs
  (defun alist-set (KEY PROP ALIST)
    (set ALIST (assoc-delete-all KEY (symbol-value ALIST)))
    (add-to-list ALIST (cons KEY PROP)))
  (alist-set "\\.pdf\\'" document-view 'org-file-apps)
  (alist-set "\\.djvu\\'" document-view 'org-file-apps)
  ;; C-c C-s RET inserts block. See ":exports both" for results.
  ;; TODO: Section 5 in https://blog.d46.us/advanced-emacs-startup/
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((calc . t)
     (octave . t)
     (maxima . t)
     (R . t)
     (python . t) ; see https://emacs.stackexchange.com/a/64539
     (shell . t)))
  ;; Resize Org headings
  (custom-set-faces
   '(org-document-title ((t (:height 1.6))))
   '(outline-1          ((t (:height 1.25))))
   '(outline-2          ((t (:height 1.2))))
   '(outline-3          ((t (:height 1.15))))
   '(outline-4          ((t (:height 1.1))))
   '(outline-5          ((t (:height 1.1))))
   '(outline-6          ((t (:height 1.1))))
   '(outline-8          ((t (:height 1.1))))
   '(outline-9          ((t (:height 1.1)))))
  ;; Declutter (e.g. prettify leading stars)
  (setq ;; TODO org-adapt-indentation t
   ;; TODO        org-hide-leading-stars t
   ;; TODO        org-pretty-entities t
   ;; TODO org-ellipsis "  ·"
   )
  ;; Make source blocks nicer
  (setq org-src-fontify-natively t
        org-src-tab-acts-natively t
        org-edit-src-content-indentation 0)
  ;; Make TODOs and headers nice
  (setq org-log-done                       t
        org-auto-align-tags                t
        org-tags-column                    -80
        org-fold-catch-invisible-edits     'show-and-error
        org-special-ctrl-a/e               t
        org-insert-heading-respect-content t)
  ;; Show inline images
  (setq org-startup-with-inline-images t)
  (setq org-babel-python-command
        "python3") ; add ":python python" to block for python2
  ;; Automagically save org-buffers after org-refile moves stuff
  (defun my-org-refile (&optional goto default-buffer rfloc msg)
    (interactive "P")
    "Does an ~org-refile~ and then a ~org-save-all-org-buffers~."
    (org-refile goto default-buffer rfloc msg) (org-save-all-org-buffers))
  (define-key org-mode-map (kbd "C-c C-w") 'my-org-refile)
  ;; F8 opens GTD file
  (global-set-key (kbd "<f8>") (lambda() (interactive)(find-file gtd-gtd)))
  )
(use-package suomalainen-kalenteri
  :ensure t
  :after org
  :config
  (set-face-attribute 'org-agenda-calendar-sexp nil
                      :inherit 'org-level-2)
  )
(use-package org-appear
  :ensure t
  :commands (org-appear-mode)
  :hook     (org-mode . org-appear-mode)
  :config
  (setq org-hide-emphasis-markers t)  ; Must be activated for org-appear to work
  (setq org-appear-autoemphasis   t   ; Show bold, italics, verbatim, etc.
	org-appear-autosubmarkers t)) ; Show sub- and superscripts
;; Style bullets in org-mode
(use-package org-superstar
  :ensure t
  :after org
  :config
  (setq org-superstar-leading-bullet 8229)
  (setq org-superstar-headline-bullets-list '("◆" "◇" "•" "⚬" "●" "○"))
;;  (setq org-superstar-special-todo-items t) ;; Makes TODO header bullets into boxes
  ;; (setq org-superstar-todo-bullet-alist '(("TODO"  . 9744)
  ;;                                         ("MEET"  . 9744)
  ;;                                         ("WAIT"  . 9744)
  ;;                                         ("DONE"  . 9745)
  ;;                                         ("KILL"  . 9745)))
  :hook (org-mode . org-superstar-mode))
(use-package org-fragtog ; toggle LaTeX previews automatically, like org-appear
  :ensure t
  :after org
  :hook (org-mode . org-fragtog-mode))
;; Use svg's for tags, dates etc. in org-mode
(use-package svg-tag-mode
  :ensure t
  :after org
  :hook (org-mode . svg-tag-mode)
  :config
  (defconst date-re "[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}")
  (defconst time-re "[0-9]\\{2\\}:[0-9]\\{2\\}")
  (defconst day-re "[A-Za-z]\\{3\\}")
  (defconst day-time-re (format "\\(%s\\)? ?\\(%s\\)?" day-re time-re))
  (defconst day-time-time-re (format "\\(%s\\)? ?\\(%s\\)?-?\\(%s\\)?" day-re time-re time-re))

  (defun svg-progress-percent (value)
    (svg-image (svg-lib-concat
		(svg-lib-progress-bar (/ (string-to-number value) 100.0)
			              nil :margin 0 :stroke 2 :radius 3 :padding 2 :width 11)
		(svg-lib-tag (concat value "%")
			     nil :stroke 0 :margin 0)) :ascent 'center))

  (defun svg-progress-count (value)
    (let* ((seq (mapcar #'string-to-number (split-string value "/")))
           (count (float (car seq)))
           (total (float (cadr seq))))
      (svg-image (svg-lib-concat
		  (svg-lib-progress-bar (/ count total) nil
					:margin 0 :stroke 2 :radius 3 :padding 2 :width 11)
		  (svg-lib-tag value nil
			       :stroke 0 :margin 0)) :ascent 'center)))
  (setq svg-tag-tags
        `(;; Org tags
          ;; (":\\([A-Za-z0-9]+\\)" . ((lambda (tag) (svg-tag-make tag))))
          ;; (":\\([A-Za-z0-9]+[ \-]\\)" . ((lambda (tag) tag)))

          ;; Task priority
          ("\\[#[A-Z]\\]" . ( (lambda (tag)
                                (svg-tag-make tag :face 'org-priority
                                              :beg 2 :end -1 :margin 0))))

          ;; Progress
          ("\\(\\[[0-9]\\{1,3\\}%\\]\\)" . ((lambda (tag)
                                              (svg-progress-percent (substring tag 1 -2)))))
          ("\\(\\[[0-9]+/[0-9]+\\]\\)" . ((lambda (tag)
                                            (svg-progress-count (substring tag 1 -1)))))

          ;; ;; TODO / DONE
          ;; ("TODO" . ((lambda (tag) (svg-tag-make "TODO"
          ;;                                        :face 'org-todo
          ;;                                        :inverse t
          ;;                                        :margin 0))))
          ;; ("MEET" . ((lambda (tag) (svg-tag-make "MEET"
          ;;                                        :face (cdr (assoc "MEET" org-todo-keyword-faces))
          ;;                                        :margin 0))))
          ;; ("WAIT" . ((lambda (tag) (svg-tag-make "WAIT"
          ;;                                        :face 'org-todo
          ;;                                        :inverse t
          ;;                                        :margin 0))))
          ;; ("DONE" . ((lambda (tag) (svg-tag-make "DONE"
          ;;                                        :face 'org-done
          ;;                                        :margin 0))))
          ;; ("KILL" . ((lambda (tag) (svg-tag-make "KILL"
          ;;                                        :face 'org-done
          ;;                                        :margin 0))))

          ;; Active date (with or without day name, with or without time)
          (,(format "\\(<%s>\\)" date-re) .
           ((lambda (tag)
              (svg-tag-make tag :beg 1 :end -1 :margin 0))))
          (,(format "\\(<%s \\)%s>" date-re day-time-re) .
           ((lambda (tag)
              (svg-tag-make tag :beg 1 :inverse nil :crop-right t :margin 0))))
          (,(format "<%s \\(%s>\\)" date-re day-time-re) .
           ((lambda (tag)
              (svg-tag-make tag :end -1 :inverse t :crop-left t :margin 0))))
          (,(format "\\(<%s \\)%s>" date-re day-time-time-re) .
           ((lambda (tag)
              (svg-tag-make tag :beg 1 :inverse nil :crop-right t :margin 0))))
          (,(format "<%s \\(%s>\\)" date-re day-time-time-re) .
           ((lambda (tag)
              (svg-tag-make tag :end -1 :inverse t :crop-left t :margin 0))))

          ;; Inactive date  (with or without day name, with or without time)
          (,(format "\\(\\[%s\\]\\)" date-re) .
           ((lambda (tag)
              (svg-tag-make tag :beg 1 :end -1 :margin 0 :face 'org-date))))
          (,(format "\\(\\[%s \\)%s\\]" date-re day-time-re) .
           ((lambda (tag)
              (svg-tag-make tag :beg 1 :inverse nil :crop-right t :margin 0 :face 'org-date))))
          (,(format "\\[%s \\(%s\\]\\)" date-re day-time-re) .
           ((lambda (tag)
              (svg-tag-make tag :end -1 :inverse t :crop-left t :margin 0 :face 'org-date))))
          (,(format "\\(\\[%s \\)%s\\]" date-re day-time-time-re) .
           ((lambda (tag)
              (svg-tag-make tag :beg 1 :inverse nil :crop-right t :margin 0 :face 'org-date))))
          (,(format "\\[%s \\(%s\\]\\)" date-re day-time-time-re) .
           ((lambda (tag)
              (svg-tag-make tag :end -1 :inverse t :crop-left t :margin 0 :face 'org-date)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;



;; Make garbage collection more frequent now after initialization
(setq gc-cons-threshold (* 2 1000 1000))


